package com.oly.cms.admin.service.impl;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oly.cms.admin.mapper.CmsArticleLiquidMapper;
import com.oly.cms.admin.mapper.CmsArticleMapper;
import com.oly.cms.admin.mapper.CmsThemeMapper;
import com.oly.cms.admin.model.param.ArticleBenchParam;
import com.oly.cms.admin.service.ICmsArticleService;
import com.oly.cms.common.constant.CmsCacheConstant;
import com.oly.cms.common.constant.OlySystemConstant;
import com.oly.cms.common.domain.VisibleParam;
import com.oly.cms.common.domain.entity.CmsArticle;
import com.oly.cms.common.domain.entity.CmsCategory;
import com.oly.cms.common.domain.entity.CmsTag;
import com.oly.cms.common.domain.entity.CmsTheme;
import com.oly.cms.common.domain.vo.ArticleVo;
import com.oly.cms.common.event.CacheWebRefreshAllEvent;
import com.oly.cms.common.model.properties.OlyCmsConfigProperties;
import com.oly.cms.common.model.properties.OlyWebConfigProperties;
import com.oly.cms.general.mapper.CategorySearchMapper;
import com.oly.cms.general.mapper.TagSearchMapper;
import com.grace.common.constant.UserConstants;
import com.grace.common.core.text.Convert;
import com.grace.common.exception.ServiceException;
import com.grace.system.service.impl.SysSearchConfigServiceImpl;

@Service
public class CmsArticleServiceImpl implements ICmsArticleService {

	@Autowired
	private ApplicationEventPublisher app;
	@Autowired
	private CmsArticleMapper articleMapper;
	@Autowired
	private TagSearchMapper tagSearchMapper;
	@Autowired
	private CategorySearchMapper categorySearchMapper;
	@Autowired
	private CmsThemeMapper themeMapper;
	@Autowired
	private CmsArticleLiquidMapper cmsArticleLiquidMapper;
	@Autowired
	private SysSearchConfigServiceImpl configService;

	/**
	 * 先插入文章 获取文章id 插入标签 插入分类
	 * 
	 * @param arVo
	 * @return
	 */
	@Transactional
	@Override
	public int insertCmsArticle(ArticleVo arVo) {
		Long cats[] = cmsArticleLiquidMapper.filterCats(arVo.getCats());
		int maxCat = Integer.parseInt(configService.selectConfigDefaultValue(
				OlyCmsConfigProperties.CMS_CONFIG_GROUP.defaultValue(), OlyCmsConfigProperties.ARTICLE_CAT_MAXNUM));
		if (cats.length < 0 || cats.length > maxCat) {
			throw new ServiceException("必须保持一个分类,且最多为" + maxCat);
		}
		int maxTag = Integer.parseInt(configService.selectConfigDefaultValue(
				OlyCmsConfigProperties.CMS_CONFIG_GROUP.defaultValue(), OlyCmsConfigProperties.ARTICLE_TAG_MAXNUM));
		if (arVo.getTags() != null && arVo.getTags().length > maxTag) {
			throw new ServiceException("关联标签数量不能超过" + maxTag);
		}
		arVo.setArticleId(null);
		// 验证文章
		if (!this.checkArticleUnique(arVo)) {
			CmsArticle art = arVo;
			// 顶置默认
			art.setArticleTop(OlySystemConstant.DEFAULT_POST_TOP);
			// 状态默认审核中
			art.setVisible(Integer.parseInt(
					configService.selectConfigDefaultValue(OlyCmsConfigProperties.CMS_CONFIG_GROUP.defaultValue(),
							OlyCmsConfigProperties.ARTICLE_VISIBLE_DEFAULT)));
			// 插入文章
			int reInsertNum = articleMapper.insertCmsArticle(art);
			arVo.setArticleId(art.getArticleId());
			// 插入关联分类
			cmsArticleLiquidMapper.insertCmsArticleCats(art.getArticleId(), arVo.getCats());
			// 更新分类关联文章数
			cmsArticleLiquidMapper.updateCmsCatCountByIds(arVo.getCats());

			// 验证标签是否存在|过滤不存在的标签
			if (arVo.getTags() != null) {
				Long ts[] = cmsArticleLiquidMapper.filterTags(arVo.getTags());
				if (ts.length > 0) {
					// 插入关联标签
					cmsArticleLiquidMapper.insertCmsArticleTags(art.getArticleId(), ts);
					cmsArticleLiquidMapper.updateCmsTagCountByIds(ts);
				}
			}
			// 插入文章相关统计
			cmsArticleLiquidMapper.insertCmsArticleCount(art.getArticleId());
			// 关联主题
			insertArticleTheme(art.getArticleId());
			app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.POST_CACHE_KEY_PREFIX));
			return reInsertNum;
		} else {
			throw new ServiceException("参数验证校验失败,请检查！");
		}
	}

	/**
	 * 删除关联cat 删除关联tag,批量删除文章
	 */
	@Transactional
	@Override
	public int deleteCmsArticleByIds(Long[] articleIds) {
		Long[] catIds = cmsArticleLiquidMapper.selectCatIdsByArticleIds(articleIds);
		Long[] tagIds = cmsArticleLiquidMapper.selectTagIdsByArticleIds(articleIds);
		cmsArticleLiquidMapper.deleteArticleTagByIds(articleIds);
		cmsArticleLiquidMapper.deleteArticleCatByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsCommentByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsCommentRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsCollectRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsLookRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsLikeRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsNastyRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsShareRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsScoreRecordByIds(articleIds);
		cmsArticleLiquidMapper.deleteCmsArticleCountByIds(articleIds);
		articleMapper.deleteCmsArticleByIds(articleIds);
		this.updateCount(catIds, tagIds);
		app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.POST_CACHE_KEY_PREFIX));
		return articleIds.length;
	}

	/**
	 * 批量更新顶置
	 * 
	 * @param benchParam
	 * @return
	 */
	@Override
	public int batchArticleTop(ArticleBenchParam benchParam) {
		int re = articleMapper.benchArticleTop(benchParam);
		app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.POST_CACHE_KEY_PREFIX));
		return re;
	}

	/**
	 * 批量更新状态
	 * 
	 * @param benchParam
	 * @return
	 */
	@Override
	public int batchArticleVisible(ArticleBenchParam benchParam) {
		int re = articleMapper.benchArticleVisible(benchParam);
		app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.POST_CACHE_KEY_PREFIX));
		return re;
	}

	/**
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ArticleVo selectCmsArticleById(Long id) {
		return articleMapper.selectCmsArticleById(id);
	}

	@Override
	public List<CmsArticle> listCmsArticle(ArticleVo artVo) {
		return articleMapper.listCmsArticle(artVo);
	}

	@Override
	@Transactional
	public int updateCmsArticleById(ArticleVo cmsArticle) {
		// 修改文章
		if (!this.checkArticleUnique(cmsArticle) && cmsArticle.getArticleId() != null) {
			this.updateArticleCategory(cmsArticle.getArticleId(), cmsArticle.getCats());
			this.updateArticleTag(cmsArticle.getArticleId(), cmsArticle.getTags());
			this.updateArticleThemeByArticleId(cmsArticle.getArticleId());
			return articleMapper.updateCmsArticleById(cmsArticle);
		} else {
			throw new ServiceException("参数验证校验失败,请检查！");
		}

	}

	/** 参数验证 */
	@Override
	public boolean checkArticleUnique(CmsArticle cmsArticle) {
		CmsArticle c = articleMapper.checkArticleUnique(cmsArticle);
		Long articleId = cmsArticle.getArticleId() == null ? -1L : cmsArticle.getArticleId();
		if (c == null || c.getArticleId().longValue() == articleId.longValue()) {
			return UserConstants.UNIQUE;
		}
		return UserConstants.NOT_UNIQUE;
	}

	/**
	 * 更新关联分类文章
	 * 
	 * @param articleId
	 * @param catId
	 * @return
	 */
	private int updateArticleCategory(Long articleId, Long[] catIds) {
		if (catIds == null || catIds.length == 0) {
			return 0;
		}
		int re = 0;
		Long[] asr = new Long[] { articleId };
		Long[] oldCatIds = cmsArticleLiquidMapper.selectCatIdsByArticleIds(asr);
		if (CollectionUtils.isEqualCollection(Arrays.asList(catIds), Arrays.asList(oldCatIds))) {
			return re;
		}
		// 清空分类关联
		cmsArticleLiquidMapper.deleteArticleCatByIds(asr);
		Long sc[] = cmsArticleLiquidMapper.filterCats(catIds);
		if (sc.length == 0) {
			throw new ServiceException("请确保必须关联一个有效分类");
		} else if (cmsArticleLiquidMapper.countArticleCat(articleId) >= Integer
				.parseInt(configService.selectConfigDefaultValue(OlyCmsConfigProperties.CMS_CONFIG_GROUP.defaultValue(),
						OlyCmsConfigProperties.ARTICLE_CAT_MAXNUM))) {
			throw new ServiceException("关联失败,关联分类已达上限,文章Id" + articleId);
		} else {
			// 重新关联
			re = cmsArticleLiquidMapper.insertCmsArticleCats(articleId, sc);
			// 并集
			Collection<Long> o = CollectionUtils.union(Arrays.asList(oldCatIds), Arrays.asList(sc));
			// 更新分类的统计
			cmsArticleLiquidMapper.updateCmsCatCountByIds(o.toArray(new Long[o.size()]));
		}
		return re;
	}

	/**
	 * 更新关联标签文章
	 * 
	 * @param articleId
	 * @param tagId
	 * @return
	 */
	private int updateArticleTag(Long articleId, Long[] tagIds) {
		if (tagIds == null || tagIds.length == 0) {
			return 0;
		}
		int re = 0;
		Long[] asr = new Long[] { articleId };
		Long[] oldTagIds = cmsArticleLiquidMapper.selectTagIdsByArticleIds(asr);
		if (CollectionUtils.isEqualCollection(Arrays.asList(tagIds), Arrays.asList(oldTagIds))) {
			return re;
		}
		// 清空标签关联
		cmsArticleLiquidMapper.deleteArticleTagByIds(asr);
		Long ts[] = {};
		if (tagIds.length != 0) {
			ts = cmsArticleLiquidMapper.filterTags(tagIds);
		}
		if (ts.length == 0) {
			return 0;
		} else if (ts.length >= Integer
				.parseInt(configService.selectConfigDefaultValue(OlyCmsConfigProperties.CMS_CONFIG_GROUP.defaultValue(),
						OlyCmsConfigProperties.ARTICLE_TAG_MAXNUM))) {
			throw new ServiceException("关联标签数量超出限制");
		} else {
			re = cmsArticleLiquidMapper.insertCmsArticleTags(articleId, ts);
			// 并集
			Collection<Long> o = CollectionUtils.union(Arrays.asList(oldTagIds), Arrays.asList(ts));
			cmsArticleLiquidMapper.updateCmsTagCountByIds(o.toArray(new Long[o.size()]));
		}
		return re;
	}

	/**
	 * 过滤 重复选择分类
	 */
	@Override
	public Long[] filterCats(Long[] cats) {
		return cmsArticleLiquidMapper.filterCats(cats);
	}

	/**
	 * 过滤 重复选择标签
	 */
	@Override
	public Long[] filterTags(Long[] tags) {
		return cmsArticleLiquidMapper.filterTags(tags);
	}

	/**
	 * 重建索引
	 */
	@Override
	public int buildArticleIndex(String themeName) {
		Integer[] supportTypes = Convert.toIntArray(
				configService.selectConfigValueByGk(themeName, OlyWebConfigProperties.ARTICLE_TYPES.getValue()));
		// 支持所有文章 所有文章不需要关联
		cmsArticleLiquidMapper.deleteCmsArticleThemeByTheme(themeName);
		int count = 0;
		if (supportTypes != null) {
			for (Integer support : supportTypes) {
				CmsCategory CmsCategory = new CmsCategory();
				CmsCategory.setCatType(support);
				List<CmsCategory> cats = categorySearchMapper.listCmsCats(CmsCategory);
				for (CmsCategory cat : cats) {
					ArticleVo artVo = new ArticleVo();
					artVo.setCatId(cat.getCatId());
					List<CmsArticle> arts = articleMapper.listCmsArticle(artVo);
					for (CmsArticle art : arts) {
						cmsArticleLiquidMapper.insertCmsArticleTheme(art.getArticleId(), themeName);
						count++;
					}
				}
			}
		}
		app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.POST_CACHE_KEY_PREFIX));
		return count;
	}

	private void updateCount(Long[] catIds, Long[] tagIds) {
		if (!ArrayUtils.isEmpty(catIds)) {
			cmsArticleLiquidMapper.updateCmsCatCountByIds(catIds);
		}
		if (!ArrayUtils.isEmpty(tagIds)) {
			cmsArticleLiquidMapper.updateCmsTagCountByIds(tagIds);
		}
	}

	/**
	 * 关联主题
	 * 
	 * @param articleId
	 */
	private void insertArticleTheme(long articleId) {
		List<CmsTheme> themes = themeMapper.selectCmsThemeList(null);
		if (themes == null) {
			return;
		}
		// 不管是否隐藏均可关联
		VisibleParam vParam = new VisibleParam();
		vParam.setId(articleId);
		List<Integer> tagTypes = tagSearchMapper.listCmsTagByArticleId(vParam).stream().map(CmsTag::getTagType)
				.collect(Collectors.toList());
		List<Integer> catTypes = categorySearchMapper.listCmsCatByArticleId(vParam).stream()
				.map(CmsCategory::getCatType)
				.collect(Collectors.toList());
		// 合并
		tagTypes.addAll(catTypes);
		// 去重
		List<Integer> types = tagTypes.stream().distinct().collect(Collectors.toList());
		for (CmsTheme theme : themes) {
			String themeName = theme.getWebName() + "_" + theme.getThemeName();
			Integer[] supportTypes = Convert.toIntArray(
					configService.selectConfigValueByGk(themeName, OlyWebConfigProperties.ARTICLE_TYPES.getValue()));
			if (supportTypes == null || CollectionUtils.intersection(types, Arrays.asList(supportTypes)) != null) {
				cmsArticleLiquidMapper.insertCmsArticleTheme(articleId, themeName);
			}
		}
	}

	/**
	 * 
	 * @param articleId
	 */
	private void updateArticleThemeByArticleId(long articleId) {
		cmsArticleLiquidMapper.deleteCmsArticleThemeByArticleId(articleId);
		insertArticleTheme(articleId);
	}

	@Override
	public Long[] selectTagIdsByArticleIds(Long[] articleIds) {

		return cmsArticleLiquidMapper.selectTagIdsByArticleIds(articleIds);
	}

	@Override
	public Long[] selectCatIdsByArticleIds(Long[] articleIds) {
		return cmsArticleLiquidMapper.selectCatIdsByArticleIds(articleIds);
	}

	@Override
	@Transactional
	public int batchArticleCategory(ArticleVo articleVo) {
		updateArticleCategory(articleVo.getArticleId(), articleVo.getCats());
		this.updateArticleThemeByArticleId(articleVo.getArticleId());
		return updateArticleUpdateBy(articleVo.getArticleId(), articleVo.getUpdateBy());
	}

	@Override
	@Transactional
	public int batchArticleTag(ArticleVo articleVo) {
		updateArticleTag(articleVo.getArticleId(), articleVo.getCats());
		this.updateArticleThemeByArticleId(articleVo.getArticleId());
		return updateArticleUpdateBy(articleVo.getArticleId(), articleVo.getUpdateBy());
	}

	@Override
	public int updateArticleUpdateBy(Long articleId, String updateBy) {

		return articleMapper.updateArticleUpdateBy(articleId, updateBy);
	}

}
